package com.crazymaker.springcloud.ratelimit;

import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;

@Slf4j
public class CounterLimiter {

    private static long startTime = System.currentTimeMillis();

    private static final long interval = 1000;

    // 1秒内最多通过2次请求
    private static final int maxCount = 2;

    // 计数器
    private static AtomicInteger counter = new AtomicInteger(0);

    private static ReentrantLock lock = new ReentrantLock(true);

    public static int tryAcquire(String taskId, int turn) {
        long now = System.currentTimeMillis();
        if (now < startTime + interval) {
            int count = counter.getAndIncrement();
            if (count > maxCount) {
                return -count;
            } else {
                return count;
            }
        } else {
            log.info("新时间区到了,taskId{}, turn {}..", taskId, turn);
//            synchronized (CounterLimiter.class) {
//                // 在判断一次，防止重复初始化
//                if (now > startTime + interval) {
//                    counter.set(0);
//                    startTime = now;
//                }
//            }

            try {
                lock.lock();
                if (now > startTime + interval) {
                    counter.set(0);
                    startTime = now;
                }
            } finally {
                lock.unlock();
            }
            return 0;
        }
    }

    ExecutorService executorService = Executors.newFixedThreadPool(5);

    private static final int threadCount = 200;


    @Test
    public void testLimit() throws Exception {
        CountDownLatch latch = new CountDownLatch(5);
        AtomicInteger failedCount = new AtomicInteger();
        long start = System.currentTimeMillis();
        for (int i = 0; i < 5; i++) {
            executorService.submit(new Runnable() {
                @Override
                public void run() {
                    try {
                        String taskId = String.valueOf(Thread.currentThread().getId());
                        for (int j = 0; j < 20; j++) {
                            int count = CounterLimiter.tryAcquire("taskId" + taskId, 2);
                            if (count <= 0) {
                                // 失败的次数
                                failedCount.incrementAndGet();
                            }
                            Thread.sleep(200);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        latch.countDown();
                    }
                }
            });
        }

        latch.await();
        long end = System.currentTimeMillis() - start;
        log.info("失败的次数:{}", failedCount.get());
        log.info("成功的次数:{}", (5 * 20) - failedCount.get());
        log.info("失败的比例:{}", failedCount.get() / 100F);
        log.info("耗时:{}", end / 1000F);
    }
}
